package com.piggy.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.piggy.common.core.constant.UserConstants;
import com.piggy.common.core.enums.UserStatus;
import com.piggy.common.core.exception.CustomException;
import com.piggy.common.core.exception.base.BaseException;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.common.datascope.annotation.DataScope;
import com.piggy.system.api.domain.SysRole;
import com.piggy.system.api.domain.SysRoleSceneRl;
import com.piggy.system.api.domain.SysUser;
import com.piggy.system.api.domain.SysUserRole;
import com.piggy.system.domain.SysRoleDept;
import com.piggy.system.domain.SysRoleMenu;
import com.piggy.system.mapper.SysRoleDeptMapper;
import com.piggy.system.mapper.SysRoleMapper;
import com.piggy.system.mapper.SysRoleMenuMapper;
import com.piggy.system.mapper.SysUserRoleMapper;
import com.piggy.system.service.ISysRoleSceneRlService;
import com.piggy.system.service.ISysRoleService;
import com.piggy.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 角色 业务层处理
 *
 * @author shark
 */
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {

    @Autowired
    private SysRoleMenuMapper roleMenuMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private SysRoleDeptMapper roleDeptMapper;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private ISysRoleSceneRlService sysRoleSceneRlService;

    @Override
    @DataScope(deptAlias = "d")
    public TableDataInfo<SysRole> selectPageRoleList(SysRole role) {
        return PageUtils.buildDataInfo(baseMapper.selectPageRoleList(PageUtils.buildPage(), role));
    }

    /**
     * 根据条件分页查询角色数据
     *
     * @param role 角色信息
     * @return 角色数据集合信息
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<SysRole> selectRoleList(SysRole role) {
        return baseMapper.selectRoleList(role);
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<SysRole> perms = baseMapper.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (SysRole perm : perms) {
            if (Validator.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRoleAll() {
        return this.selectRoleList(new SysRole());
    }

    /**
     * 根据用户ID获取角色选择框列表
     *
     * @param userId 用户ID
     * @return 选中角色ID列表
     */
    @Override
    public List<Integer> selectRoleListByUserId(Long userId) {
        return baseMapper.selectRoleListByUserId(userId);
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    @Override
    public SysRole selectRoleById(Long roleId) {
        return getById(roleId);
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleNameUnique(SysRole role) {
        Long roleId = Validator.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleName, role.getRoleName()).last("limit 1"));
        if (Validator.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public String checkRoleKeyUnique(SysRole role) {
        Long roleId = Validator.isNull(role.getRoleId()) ? -1L : role.getRoleId();
        SysRole info = getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getRoleKey, role.getRoleKey()).last("limit 1"));
        if (Validator.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色是否允许操作
     *
     * @param role 角色信息
     */
    @Override
    public void checkRoleAllowed(SysRole role) {
        if (Validator.isNotNull(role.getRoleId()) && role.isAdmin()) {
            throw new CustomException("不允许操作超级管理员角色");
        }
    }

    /**
     * 通过角色ID查询角色使用数量
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    public int countUserRoleByRoleId(Long roleId) {
        Long count =  userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
        return count.intValue();
    }

    /**
     * 新增保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int insertRole(SysRole role) {
        // 新增角色信息
        baseMapper.insert(role);
        return insertRoleMenu(role);
    }

    /**
     * 修改保存角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int updateRole(SysRole role) {
        // 修改角色信息
        baseMapper.updateById(role);
        // 删除角色与菜单关联
        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, role.getRoleId()));
        return insertRoleMenu(role);
    }

    /**
     * 修改角色状态
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int updateRoleStatus(SysRole role) {
        int res =  baseMapper.updateById(role);
        // 处理角色缓存问题
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, role.getRoleId()));
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> userList = new ArrayList<>();
            userRoleList.forEach(t-> {
                userList.add(t.getUserId());
            });
            userService.remove(userList);
        }
        return res;
    }

    /**
     * 修改数据权限信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    @Transactional
    public int authDataScope(SysRole role) {
        // 修改角色信息
        baseMapper.updateById(role);
        // 删除角色与部门关联
        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, role.getRoleId()));
        // 新增角色和部门信息（数据权限）
        int res = insertRoleDept(role);
        // 处理角色缓存问题
        removeRoleUserCache(role.getRoleId());
        return res;
    }

    /**
     * 新增角色菜单信息
     *
     * @param role 角色对象
     */
    public int insertRoleMenu(SysRole role) {
        int rows = 1;
        // 新增用户与角色管理
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        for (Long menuId : role.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(role.getRoleId());
            rm.setMenuId(menuId);
            list.add(rm);
        }
        if (list.size() > 0) {
			rows = roleMenuMapper.batchRoleMenu(list);
        }
        return rows;
    }

    /**
     * 新增角色部门信息(数据权限)
     *
     * @param role 角色对象
     */
    public int insertRoleDept(SysRole role) {
        int rows = 1;
        // 新增角色与部门（数据权限）管理
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        for (Long deptId : role.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(role.getRoleId());
            rd.setDeptId(deptId);
            list.add(rd);
        }
        if (list.size() > 0) {
			rows = roleDeptMapper.batchRoleDept(list);
        }
        return rows;
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteRoleById(Long roleId) {
        // 删除角色与菜单关联
        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
        // 删除角色与部门关联
        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, roleId));
        int res = baseMapper.deleteById(roleId);
        // 处理角色缓存问题
        removeRoleUserCache(roleId);
        return res;
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            checkRoleAllowed(new SysRole(roleId));
            SysRole role = selectRoleById(roleId);
            if (countUserRoleByRoleId(roleId) > 0) {
                throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName()));
            }
        }
        List<Long> ids = Arrays.asList(roleIds);
        // 删除角色与菜单关联
        roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
        // 删除角色与部门关联
        roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
        int res = baseMapper.deleteBatchIds(ids);

        // 处理角色缓存问题
        removeRoleUserCache(Arrays.asList(roleIds));

        return res;
    }


	/**
	 * 取消授权用户角色
	 *
	 * @param userRole 用户和角色关联信息
	 * @return 结果
	 */
	@Override
	public int deleteAuthUser(SysUserRole userRole) {
		int res = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
			.eq(SysUserRole::getRoleId, userRole.getRoleId())
			.eq(SysUserRole::getUserId, userRole.getUserId()));

        // 处理角色缓存问题
        removeRoleUserCache(userRole.getRoleId());

        return res;
	}

	/**
	 * 批量取消授权用户角色
	 *
	 * @param roleId 角色ID
	 * @param userIds 需要取消授权的用户数据ID
	 * @return 结果
	 */
	@Override
	public int deleteAuthUsers(Long roleId, Long[] userIds) {
		int res = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
			.eq(SysUserRole::getRoleId, roleId)
			.in(SysUserRole::getUserId, Arrays.asList(userIds)));

        // 处理角色缓存问题
        removeRoleUserCache(roleId);

        return res;
    }

	/**
	 * 批量选择授权用户角色
	 *
	 * @param roleId 角色ID
	 * @param userIds 需要删除的用户数据ID
	 * @return 结果
	 */
	@Override
	public int insertAuthUsers(Long roleId, Long[] userIds) {
		// 新增用户与角色管理
		int rows = 1;
		List<SysUserRole> list = new ArrayList<SysUserRole>();
		for (Long userId : userIds) {
			SysUserRole ur = new SysUserRole();
			ur.setUserId(userId);
			ur.setRoleId(roleId);
			list.add(ur);
		}
		if (list.size() > 0) {
			rows = userRoleMapper.batchUserRole(list);
		}

        // 处理角色缓存问题
        removeRoleUserCache(roleId);

        return rows;
	}

    @Override
    public boolean checkRoleNotAdmin(Long userId) {
        // 查询角色 跳过超级管理员检查
        List<Integer> roleIds = this.selectRoleListByUserId(userId);
        if (CollUtil.isNotEmpty(roleIds)) {
            List<SysRole> roles = this.lambdaQuery().in(SysRole::getRoleId, roleIds).select(SysRole::getRoleKey).list();
            if (roles.stream().map(SysRole::getRoleKey).anyMatch(i -> i.equals("admin"))) {
                return false;
            }
        }
        return true;
    }

    @Override
    public List<SysUser> getAssignees(List<String> menuIds) {
        List<SysUser> result = CollUtil.newArrayList();
        menuIds.forEach(i -> {
            // 根据按钮id查询角色ids
            List<SysRoleMenu> roleMenuList = new LambdaQueryChainWrapper<>(roleMenuMapper)
                    .eq(SysRoleMenu::getMenuId, i).select(SysRoleMenu::getRoleId).list();
            if (CollUtil.isEmpty(roleMenuList)) {
                throw new BaseException("未查询到指派角色");
            }
            List<Long> roleIds = roleMenuList.stream().map(SysRoleMenu::getRoleId).collect(Collectors.toList());
            // 根据角色ids查询用户ids
            List<SysUserRole> userRoleList = new LambdaQueryChainWrapper<>(userRoleMapper)
                    .in(SysUserRole::getRoleId, roleIds).select(SysUserRole::getUserId).list();
            if (CollUtil.isEmpty(userRoleList)) {
                throw new BaseException("未查询到指派用户");
            }
            List<Long> userIds = userRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
            // 根据用户ids查询用户手机号
            List<SysUser> users = userService.lambdaQuery().in(SysUser::getUserId, userIds).select(SysUser::getPhonenumber).list();
            if (CollUtil.isEmpty(users)) {
                throw new BaseException("未查询到指派用户");
            }
            result.addAll(users);
        });
        return result;
    }

    @Override
    public List<SysUser> getRoleUsers(Long roleId) {
        List<SysUserRole> userRoleList = new LambdaQueryChainWrapper<>(sysUserRoleMapper)
                .eq(SysUserRole::getRoleId, roleId).select(SysUserRole::getUserId).list();

        if (CollUtil.isEmpty(userRoleList)) {
            throw new BaseException("用户不存在");
        }
        List<Long> userIds = userRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
        List<SysUser> userList = userService.lambdaQuery().in(SysUser::getUserId, userIds).list();
        return userList;
    }

    @Override
    public List<SysUser> getRoleUserByRoleIds(List<Long> roleIds) {
        LambdaQueryWrapper<SysUserRole> roleWrapper = Wrappers.lambdaQuery();
        roleWrapper.in(SysUserRole::getRoleId, roleIds);
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(roleWrapper);
        if (CollUtil.isEmpty(userRoleList)) {
            throw new BaseException("用户不存在");
        }

        List<Long> userIds = userRoleList.stream().map(SysUserRole::getUserId).collect(Collectors.toList());
        List<SysUser> userList = userService.lambdaQuery().in(SysUser::getUserId, userIds).list();
        return userList;
    }

    @Override
    public List<SysUser> getRoleUserBySceneIds(List<Long> sceneIds) {

        List<SysRoleSceneRl> sysRoleSceneRlList = sysRoleSceneRlService.lambdaQuery().in(SysRoleSceneRl::getSceneId, sceneIds)
                .eq(SysRoleSceneRl::getStatus, UserStatus.OK.getCode()).list();
        if (CollUtil.isEmpty(sysRoleSceneRlList)) {
            throw new BaseException("角色不存在");
        }

        List<Long> roleIds = sysRoleSceneRlList.stream().map(SysRoleSceneRl::getRoleId).collect(Collectors.toList());
        return getRoleUserByRoleIds(roleIds);
    }

    @Override
    public List<SysRole> queryRoleAll() {
        return selectRoleAll();
    }

    private void removeRoleUserCache(Long roleId) {
        // 处理角色缓存问题
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> userList = new ArrayList<>();
            userRoleList.forEach(t-> {
                userList.add(t.getUserId());
            });
            userService.remove(userList);
        }
    }

    private void removeRoleUserCache(List<Long> roleIds) {
        // 处理角色缓存问题
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getRoleId, roleIds));
        if (CollUtil.isNotEmpty(userRoleList)) {
            List<Long> userList = new ArrayList<>();
            userRoleList.forEach(t-> {
                userList.add(t.getUserId());
            });
            userService.remove(userList);
        }
    }
}
